﻿using System;
using System.Collections.Generic;

public enum H3DTimerType
{
    TT_Once
    //TT_Loop,还不支持
}

public class TimerParam
{
    public int exec_after_ms = 0;
    public ulong event_id = 0;
    public Action<object> cb = null;
    public object param = null;
    public H3DTimerType timetype= H3DTimerType.TT_Once;
    public TimerParam(ulong eventid, Action<object> c, object op, int eam ,H3DTimerType tt )
    {
        cb = c;
        param = op;
        event_id = eventid;
        timetype = tt;
        exec_after_ms = eam;
    }
}
public class Timer
{
    
    int m_event_index = 1;
    ulong m_begin_event_id = 0;

    SortedDictionary<ulong, TimerParam> m_event_list = new SortedDictionary<ulong, TimerParam>();

    List<TimerParam> m_trigger_params = new List<TimerParam>(10);
    ulong GenEventID(int exec_tick)
    {
        ulong event_id = (ulong)exec_tick;
        event_id = event_id << 32;
        event_id = event_id | (uint)m_event_index++;
        return event_id;
    }
    int GetTickFromEventID(ulong event_id)
    {
        event_id = event_id >> 32;
        int tick = (int)event_id;
        return tick;
    }
    int GetIndexFromEventID(ulong event_id)
    {
        event_id = event_id & 0x00000000ffffffff;
        int tick = (int)event_id;
        return tick;
    }
    public ulong AddEvent(Action<object> callback, object param, int exec_after_ms, H3DTimerType t = H3DTimerType.TT_Once)
    {
        int cur_tick = Environment.TickCount;
        int exec_tick = cur_tick + exec_after_ms;
        ulong event_id = GenEventID(exec_tick);

        m_event_list.Add(event_id, new TimerParam(event_id,callback, param, exec_after_ms,t));
        RestFirstEventID();

        return event_id;
    }
    
    void RestFirstEventID()
    {
        if (m_event_list.Count == 0)
        {
            m_begin_event_id = 0;
        }
        var v = m_event_list.GetEnumerator();
        if (v.MoveNext())
        {
            m_begin_event_id = v.Current.Key;
        }
        else
        {
            m_begin_event_id = 0;

        }
    }
    public bool DelEvent(ulong event_id)
    {
        bool bremove = m_event_list.Remove(event_id);
        RestFirstEventID();
        return bremove;
    }
    public void Update()
    {
        if(m_event_list.Count == 0)
        {
            return;
        }
        int cur_tick = Environment.TickCount;
        int tick = GetTickFromEventID(m_begin_event_id);
        if (tick - cur_tick > 0 )
        {
            return;
        }
        m_begin_event_id = 0;


        var v = m_event_list.GetEnumerator();
        while (v.MoveNext())
        {
            ulong event_id = v.Current.Key;
            int event_tick = GetTickFromEventID(event_id);
            if (event_tick - cur_tick > 0)
            {
                m_begin_event_id = event_id;
                break;
            }
            
            m_trigger_params.Add(v.Current.Value);
        }

        for (int i = 0; i < m_trigger_params.Count; i++)
        {
            Action<object> cb = m_trigger_params[i].cb;
            if (cb != null)
            {
                cb(m_trigger_params[i].param);
            }
        }
        for (int i = 0; i < m_trigger_params.Count; i++)
        {
            m_event_list.Remove(m_trigger_params[i].event_id);
        }
        m_trigger_params.Clear();
    }
}
